# -- coding: utf-8 --
"""
# MIAHX© 框架消息的 FastDDS 订阅器

**模块：MIAHX© / 框架基础服务层（FFST） / 交互框架信息表示模型（IFIRM）**

Version: 0.4.10,
Last updated: October 20, 2024

## Contributor(s)
* YAO Naiming <[naiming@iscas.ac.cn](mailto:naiming@iscas.ac.cn)>

## Change log
### v0.4.10
- .20: [优化] 优化 on_data_listener 调用，传递 topic_name 信息
### v0.4.9
- .28: [优化] 日志；ReaderListener 新增 topic_data_type 动态创建数据对象；优化 on_data_available 实现
- .6: [更新] 调整 Reader 对象 listener 属性的访问权限为 public, 便于在 Reader 对象构造后设置监听器
### v0.4.6
- .15: [新增] wait 方法, 阻塞调用线程
- .15: [修复] __enter__ 返回 self
### v0.4.5
- .16: [优化] 支持共享 participant
- .6: [修复] 修复 log 对象为 None
- .5: [新增] 初始实现

---
Copyright © 2024-2025 MIAHX Contributors, ISCAS, and ASIC. All Rights Reserved.
Licensed under Apache-2.0.
"""

import inspect
import miahx_fastdds as dds

from .participant import *

_log = logger.bind(module_name=os.path.basename(__file__))


class ReaderListener(fastdds.DataReaderListener):
    def __init__(self, topic_name: str = None, topic_data_type: fastdds.TopicDataType = None, on_data_listeners=None):
        """
        创建 ReaderListener

        :param topic_name: 主题名称
        :param topic_data_type: 主题数据类型
        :param on_data_listeners: 主题数据监听器列表，签名为 listener(data, [topic])->None，收到数据后回调
        """
        super().__init__()
        self.topic_name = topic_name
        self.topic_data_type = topic_data_type
        self.on_data_listeners = on_data_listeners

    def on_data_available(self, reader):
        # 处理接收到的订阅数据
        try:
            info = fastdds.SampleInfo()
            create_data = getattr(dds, self.topic_data_type.getName())
            data = create_data()
            if reader.take_next_sample(data, info) == fastdds.ReturnCode_t.RETCODE_OK:
                if info.valid_data:
                    self.notify_all_listeners(data)
        except Exception as ex:
            _log.error(f'{ex}')

    def on_subscription_matched(self, datareader, info):
        matched = 'matched' if 0 < info.current_count_change else 'unmatched'
        _log.debug(f"Subscriber {matched} publisher {info.last_publication_handle}")

    def notify_all_listeners(self, data):
        """
        回调所有 data_listener 函数，传递接收到的数据
        :param data: Topic 数据
        """
        if isinstance(self.on_data_listeners, list) or isinstance(self.on_data_listeners, tuple):
            for listener in self.on_data_listeners:
                # TODO: 需将全部listener改成2参数接口
                sig = inspect.signature(listener)
                if len(sig.parameters) == 1:
                    listener(data)
                elif len(sig.parameters) == 2:
                    listener(data, self.topic_name)

    def shutdown(self):
        # 派生类清理资源
        pass


class Reader:
    def __init__(self, participant: Participant, topic_name: str,
                 topic_data_type: fastdds.TopicDataType, listener=None):
        """
        创建 DataReader，接收 Topic 数据。
        如果 Participant 中尚未创建 Topic 和 Subscriber，则新建。

        :param participant: 参与者对象
        :param topic_name: 主题名称，由 Topics 类定义
        :param topic_data_type: 主题数据类型，由 IDL 定义并包装为 Python 类型
        :param listener: ReaderListener 监听器对象
        """
        if participant is None:
            raise ValueError('participant')

        self.topic_name = topic_name
        self.listener = listener

        topic = participant.add_topic(topic_name, topic_data_type)
        subscriber = participant.add_subscriber(SubscriberQosTypes.DEFAULT)
        r_qos = fastdds.DataReaderQos()
        subscriber.get_default_datareader_qos(r_qos)
        self._reader = subscriber.create_datareader(topic, r_qos, listener)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.listener is not None:
            self.listener.shutdown()

    def wait(self, event: threading.Event):
        """
        阻塞调用线程, 直到给定的 event 被 set

        :param event: 阻塞事件对象
        """
        if event is not None:
            event.wait()
